Pro ASP.NET Core MVC2(第7版)翻译

第13章:使用 Visual Studio Code

作者:Adam Freeman 翻译:陈广 日期:2018-9-6


本章我将向您展示如何使用 Visual Studio Code 创建 ASP.NET Core MVC 应用程序,这是微软出品的一个开源跨平台编辑器。尽管名称相近,但 Visual Studio Code 与 Visual Studio 无关,它基于 Electron 框架,这是其他 Web 应用程序框架(如Angular)开发人员流行的 Atom 编辑器所使用的。

Visual Studio Code 支持 Windows、macOS 和大多数流行的 Linux 发行版。Visual Studio Code 已经成长为为一个有用的、功能齐全的开发环境,即使它缺乏 Visual Studio 提供的所有奢华功能。我发现自己越来越多地使用 Visual Studio Code,因为它使用简单、快速、对其它语言支持良好,如 JavaScript 和 TypeScript。

安装开发环境

安装 Visual Studio Code 代码的过程需要做一些工作,因为 Visual Studio 中包含的一些功能是由外部工具处理的。其中一些工具与 Visual Studio 在幕后使用的工具相同,但其他新工具对 .NET 开发世界来说并不熟悉。好消息是,这些工具被其他 Web 应用框架的开发人员广泛使用,而且质量和功能都很好。在接下来的部分中,我将向您介绍安装 Visual Studio Code 的过程,以及 MVC 开发所需的基本工具和附加组件。

安装 Node.js

在客户端开发的世界中,Node.js(也称为 Node)已经成为许多流行的开发工具所依赖的运行时。Node 创建于2009年,是用 JavaScript 编写的服务器端应用程序的简单高效运行时。它基于在 Chrome 浏览器中使用的 JavaScript 引擎,并提供了用于在浏览器环境之外执行 JavaScript 代码的 API。

作为一个应用服务器,Node.js 已经取得了一些成功,但是对于本章来说,它很有趣,因为它为新一代的跨平台构建工具和包管理器提供了基础。Node 团队的一些智能设计决策以及 Chrome JavaScript 运行时提供的跨平台支持已经为热心的工具编写者创造了机会,尤其是那些希望支持 Web 应用程序开发的人。

注意:有两个版本的 Node.js 要供使用。Long Term Support (LTS) 版本为部署到更改最小化的生产环境中提供了稳定的基础。LTS 更新每6个月发布一次,维护18个月。Current 版本是一个快速变化的版本,它倾向于新的特性而不是稳定性。在本章中,我使用了 Current 的版本。

在 Windows 下安装 Node.js

http://nodejs.org下载并运行 Windows 的 Node.js 安装程序。安装 Node.js 时,确保将其添加到路径中。图13-1显示了 Windows 安装程序,它提供了修改路径环境变量的安装选项。

图13-1 向 path 添加 Node

在 macOS 下安装 Node.js

您可以从http://nodejs.org下载 MacOS 的安装程序。运行安装程序并接受默认设置。安装完成后,确保 /usr/local/bin 在您的 $PATH 中。

在 Linux 下安装 Node.js

在 Linux 上安装 Node.js 的最简单方法是使用包管理器;Node 团队已经为 Ubuntu 的http://nodejs.org/en/download/package-manager主要发行版提供了说明,我使用清单13-1中的命令下载和安装 Node.js。

清单 13-1:安装 Node.js

sudo curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install -y nodejs

检查 Node 安装

完成安装后,打开一个新的命令提示符并运行清单13-2所示的命令,以检查 Node 是否正常工作,并显示已安装的版本。

清单 13-2:检查 Node 安装

node -v

如果安装成功并将 Node 添加到路径中,您将看到版本号。在撰写本文时,节点的当前版本为 10.9.0。如果在遵循本章中的示例时得到了意想不到的结果,请尝试使用此特定版本。

安装 Git

Visual Studio Code 包括集成 Git 支持,但是需要单独的安装来支持用于管理客户端包的 Bower 工具。

在 Windows 或 macOS 中安装 Git

https://git-scm.com/downloads下载并运行安装

在 Linux 下安装 Git

Git 已经安装在大多数 Linux 发行版上。如果您无论如何都想安装它,那么在https://git-scm.com/download/linux上查看发行版的安装说明。对于Ubuntu,我使用了清单13-3所示的命令。

清单 13-3:在 Ubuntu 下安装 Git

sudo apt-get install git

检查 Git 安装

完成安装后,在新的 命令提示符/终端 中运行清单13-4所示的命令,以检查 Git 是否已安装并可用。

清单 13-4:检查 Git 安装

git --version

此命令输出已安装的 Git 包的版本。在编写本文时,用于 Windows 和 MacOS 的 Git 的最新版本为2.16.2,用于 Linux 的 Git 的最新版本为2.16.2。

安装 Bower

Node.js 附带 Node Package Manager (NPM),用于下载和安装用 JavaScript 编写的开发包。本章唯一需要的包是 Bower,它用于管理客户端包,我在第6章中描述了它。运行清单13-5所示的命令,在 Windows 上下载和安装 Bower。

清单 13-5:在 Windows 下安装 Bower 包

npm install -g bower@1.8.4

对于 Linux 和 MacOS,使用相同的命令,但需要 sudo,如清单13-6所示。 清单 13-6:在 Linux 和 MacOS 下安装 Bower 包

sudo npm install -g bower@1.8.4

安装 .NET Core

.NET Core 运行时是 ASP.NET Core MVC 开发所必需的,每个受支持的平台都有自己的安装过程,请参见www.microsoft.com/net/core。微软为 Windows 和 MacOS 提供安装程序,并使用 tar 存档为 Linux 提供说明。

Windows 和 macOS 下安装 .NET Core

要在 Windows 或 MacOS 下安装 .NET Core,只需下载并运行 .NET Core SDK 安装程序即可。

Linux 下安装 .NET Core

Microsoft 在www.microsoft.com/net/core提供了最流行的 Linux 发行版上安装 .NET Core 的说明。我在本章中使用了 Ubuntu,这个过程需要首先使用清单13-7中所示的命令为 apt-get 设置一个新的提要。

清单 13-7:在 Ubuntu Linux 下准备安装 .NET Core

sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/xenial main" > /etc/apt/sources.list.d/dotnetdev.list'
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 417A0893
sudo apt-get update

下一步是安装 .NET Core,如清单13-8所示。

清单 13-8:在 Ubuntu Linux 下准备安装 .NET Core

sudo apt-get install dotnet-sdk-2.1.4

检查 .NET Core 安装

无论使用的是哪个平台,都可以检查 .NET Core 是否已经安装并准备使用。打开一个新的命令提示符或终端,然后运行清单13-9中的命令。

清单 13-9:检查 .NET Core 版本

dotnet --version

dotNet 命令启动 .NET 运行时,您安装的 .NET 包的版本号将显示出来。在撰写本文时,当前版本为2.1.4,但这很可能会被您阅读本书时的版本所取代。

安装 Visual Studio Code

最重要的一步是下载并安装 Visual Studio Code,它可以从http://code.visualstudio.com获得。安装包可用于 Windows、MacOS 和流行的 Linux 发行版。下载并安装所选平台的软件包。

注意:微软每月发布一个新版本的 Visual Studio Code,这意味着您安装的版本将不同于我编写此版本时的最新版本。也说明可能需要进行一些实验才能完成本章中的一些示例,尽管基本原理应该保持不变。

在 Windows 下安装 Visual Studio Code

要安装 Windows 的 Visual Studio Code,只需运行安装包。当过程完成时,Visual Studio Code 将启动,您将看到编辑器窗口,如图13-2所示。

在 macOS 下安装 Visual Studio Code

下安装 Visual Studio Code 作为 Mac 的压缩存档提供,可以从 https://go.microsoft.com/fwlink/?LinkID=620882下载。展开存档,双击它包含的 Visual Studio Code.app 文件以启动 Visual Studio Code,生成如图13-2所示的编辑器窗口。

在 Linux 下安装 Visual Studio Code

微软为 Debian 和 Ubuntu 提供了一个 .deb 文件,为 Red Hat、Fedora和 Centos 提供了一个 .rpm 文件。下载并安装您需要的 Linux 文件。由于本章使用 Ubuntu,所以我下载了 .deb 文件并使用 Ubuntu 软件工具进行安装。

安装完成后,运行清单13-10中的命令以启动 Visual Studio Code ,这将产生图13-2所示的编辑器窗口。

清单 13-10:在 Linux 下启动 Visual Studio Code

/usr/share/code/code

检查 Visual Studio Code 安装

成功安装 Visual Studio Code 的测试只需启动应用程序并查看编辑器,如图13-2所示(我改变了配色方案,因为深色的默认色并不适合为一本书创建截图)。

图13-2 在 Windows、macOS 和 Ubuntu Linux 上运行 Visual Studio Code

安装 Visual Studio Code C# 扩展

Visual Studio Code 通过扩展支持特定语言功能,尽管这些扩展与 Visual Studio 2015所支持的不同。ASP.NET Core MVC 开发最重要的扩展是增加了对 C# 的支持,这似乎是基本安装中一个奇怪的遗漏,但反映出微软将 Visual Studio Code 定位为一个通用的跨平台编辑器,它支持尽可能广泛的语言和框架。

要安装 C# 扩展,请单击 Visual Studio Code 窗口左侧的【扩展】图标。在搜索框中输入 csharp,并在列表中找到【C# for Visual Studio Code】扩展,如图13-3所示。

图13-3 定位 C# 扩展

单击【安装】按钮,Visual Studio Code 将下载并安装扩展。单击【重新加载】按钮重新启动 Visual Studio Code 并激活扩展,如图13-4所示。

图13-4 启用 C# 扩展

创建一个 ASP.NET Core 项目

Visual Studio Code 未集成创建 ASP.NET Core 项目的支持,但可以使用 dotnet 命令行创建新项目。

重要的是要创建正确的文件夹结构,以便正确设置项目,特别是在处理单元测试时。在方便的位置创建一个名为 InvitesProjects 的项目。这将是包含 ASP.NET Core MVC 和单元测试项目的文件夹。

接下来,在 InvitesProjects 文件夹中创建一个名为 PartyInvites 的文件夹,并使用命令提示符导航到该文件夹并运行清单13-11所示的命令。

清单 13-11:PartyInvites 文件夹,创建一个项目

dotnet new web --language C# --framework netcoreapp2.1

译者注:其实使用命令:
dotnet new empty
效果相同。只是以上命令可以指定 .NET Core 的版本及使用的语言

dotnet new命令提供了对项目模板的命令行方式的访问,清单13-11中指定的 Web 模板对应于我在前面几章中使用的 Visual Studio 【空】模板。表13-1描述了一组可用于 ASP.NET Core 开发的项目模板。(其他模板可用,但它们不用于 ASP.NET Core。运行dotnet new --help命令查看完整列表)。

表 13-1: ASP.NET Core 开发的 dotnet new 模板

名称 描述
web 这是前面章节中使用的空模板,它创建 ASP.NET Core 项目,但不启用 MVC 框架。
mvc 这是第2章中使用的【Web 应用程序(模型-视图-控制器)】模板,它创建了一个ASP.NET Core 项目,其中包括 MVC 框架和占位符控制器和视图。
xunit 这是 xUnit 测试项目(.NET Core)模板,它使用 xUnit 包建立单元测试,如第7章所述。

在 Visual Studio Code 中准备项目

若要在 Visual Studio Code 中打开项目,请从【文件】菜单中选择【打开文件夹】,导航到【InvitesProjects】文件夹,然后单击【选择文件夹】按钮。Visual Studio Code 将打开项目并自动安装编辑和调试 C# 应用程序所需要包。第一次开始编辑文件几秒钟后,您将看到一条消息,提示向项目添加项,如图13-5所示。

图13-5 向项目添加项的提示

单击【Yes】按钮。Visual Studio Code 将创建一个 .vscode 文件夹,并添加一些配置构建过程的文件。Visual Studio Code 默认情况下使用三段布局。侧边栏,如图13-6所示,提供了对主要功能区域的访问。

图13-6 Visual Studio Code 侧边栏

顶部按钮打开【资源管理器】窗格,该窗格显示已打开的文件夹的内容。其他按钮提供对搜索功能、集成源代码管理、调试器和已安装扩展集的访问。

单击【资源管理器】窗格中的一个文件来打开它进行编辑。多个文件可以同时编辑,您可以通过单击窗口右上角的拆分编辑器按钮来创建新的编辑器窗格。Visual Studio Code 编辑器非常棒,支持智能提示和帮助完成 NuGet 和 Bower 包的名称和版本。

除了项目文件夹的内容外,【资源管理器】窗格还显示当前正在编辑的文件,这使得您很容易将注意力集中在正在处理的文件子集上,这在处理大型项目中的相关文件子集时是一个有用的补充。

管理客户端包

Bower 用于管理 Visual Studio Code 项目中的客户端包,就像在 Visual Studio 中一样,尽管还需要一些额外的工作。

第一步是添加一个名为 .bowerrc 的文件,该文件用于告诉 Bower 安装其包的位置。右键单击 PartyInvites 文件夹并从弹出菜单中选择【新建文件】,如图13-7所示。

图13-7 创建一个新文件

将名称设置为 .bowerrc(注意文件名中有两个r)并添加如清单13-12所示的内容

清单 13-12:.bowerrc 文件的内容

{
    "directory": "wwwroot/lib"
}

接下来创建一个名为 bower,json 的文件,添加如清单13-13所示的内容。

清单 13-13:bower.json 文件的内容

{
    "name": "PartyInvites",
    "private": true,
    "dependencies": {
        "bootstrap": "4.1.3"
    }
}

使用命令 提示符/终端 来运行如清单13-14所示的命令,这个命令使用 Bower 工具下载和安装 bower.json 文件中指定的客户端包。

bower install

译者注:注意,命令一定要在【PartyInvites】文件夹下执行,而不是【InvitesProjects】文件夹

配置应用程序

项目初始化过程创建了一个不支持 MVC 的空项目。清单13-15显示了对 Startup.cs 文件的更改,使用最基本的配置设置 MVC,其中的语句将在第14章中描述。

清单 13-15:Startup.cs 文件,添加 MVC 支持

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

namespace PartyInvites
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseDeveloperExceptionPage();
            app.UseStatusCodePages();
            app.UseStaticFiles();
            app.UseMvcWithDefaultRoute();
        }
    }
}

生成并运行项目

要生成并运行项目,在 PartyInvites 目录中运行清单13-16中的命令。

清单 13-16:运行应用程序

dotnet run

Visual Studio Code 将编译项目中的代码,并使用第14节中所描述的 Kestrel 应用服务器来运行应用程序,等待5000端口的 HTTP 请求。

Visual Studio Code 不提供对 C# 类文件更改检测的支持,这意味着您必须停止应用程序,并在有更改时需要再次启动它。

要测试应用程序,请使用浏览器导航到 http://localhost:5000。您将看到如图13-8所示的响应。404错误是因为项目中目前没有控制器来处理请求。

图13-8 测试示例应用程序

重建 PartyInvites 应用程序

所有准备已完成,这意味着我可以专注于创建一个 MVC 应用程序了。我准备重建第2章中的简单的 PartyInvites 应用程序,并通过一些更改和添加来突出 Visual Studio Code 的使用。

创建模型和存储库

右键单击 PartyInvites 文件夹,并在弹出菜单中选择【新建文件夹】,如图13-9所示。将文件夹名称设置为 Models。

图13-9 新建一个文件夹

在【资源管理器】窗格中右键单击 Models 文件夹,在弹出菜单中选择【新建文件】,将名称设置为 GuestResponse.cs,并添加如清单13-17所示的 C# 代码。


使用 Visual Studio Code 编辑器

Visual Studio Code(以及本章前面安装的 C# 扩展)提供了对 C# 文件的完整编辑体验,以及常见的 Web 格式,如 JavaScript、CSS和普通 HTML 文件。在许多方面,用 Visual Studio Code 编写 MVC 应用程序与 Visual Studio 编辑器有很多共同点:有智能感知支持、颜色编码和错误高亮显示(以及修复它们的建议)。

Visual Studio Code 的主要缺陷是缺乏定制,特别是在格式化代码方面。在我写这篇文章时,有一些其他语言可以使用的配置选项,但是 C# 扩展并不允许定制,如果您喜欢的编码样式不是它默认支持的样式,这可能会使您的工作变得有点困难。但是总的来说,编辑器响应性强,易于使用,在 MacOS 或 Linux 上编写 MVC 应用程序也不像是二等体验。


清单 13-17:PartyInvites/Models 文件夹下的 GuestResponse.cs 文件的内容

using System.ComponentModel.DataAnnotations;

namespace PartyInvites.Models
{
    public class GuestResponse
    {
        public int id { get; set; }

        [Required(ErrorMessage = "Please enter your name")]
        public string Name { get; set; }

        [Required(ErrorMessage = "Please enter your email address")]
        [RegularExpression(".+\\@.+\\..+",
        ErrorMessage = "Please enter a valid email address")]
        public string Email { get; set; }
        
        [Required(ErrorMessage = "Please enter your phone number")]
        public string Phone { get; set; }

        [Required(ErrorMessage = "Please specify whether you'll attend")]
        public bool? WillAttend { get; set; }
    }
}

接下来,向 Models 文件夹中添加一个名为 IRepository.cs 的文件,并使用它来定义清单13-18所示的接口。本章中的应用程序与第2章中的应用程序之间最重要的区别是,我要将模型数据存储在持久数据库中。IRepository接口描述了应用程序将如何访问模型数据,而不指定其实现。

清单 13-18:PartyInvites/Models 文件夹下的 IRepository.cs 文件的内容

using System.Collections.Generic;

namespace PartyInvites.Models
{
    public interface IRepository
    {
        IEnumerable<GuestResponse> Responses { get; }
        void AddResponse(GuestResponse response);
    }
}

将名为 ApplicationDbContext.cs 的文件添加到 Models 文件夹中,并使用它定义清单13-19所示的数据库上下文类。

清单 13-19:PratyInvites/Models 文件夹下的 ApplicationDbContext.cs 文件的内容

using Microsoft.EntityFrameworkCore;

namespace PartyInvites.Models
{
    public class ApplicationDbContext : DbContext
    {
        public ApplicationDbContext() { }
        protected override void OnConfiguring(DbContextOptionsBuilder builder)
        {
            builder.UseSqlite("Filename=./PartyInvites.db");
        }
        public DbSet<GuestResponse> Invites { get; set; }
    }
}

SQLite 将其数据存储在由上下文类指定的文件中。对于示例应用程序,数据将存储在一个名为 PartyInvites.db 的文件中,该文件是在OnConfiguring方法中定义的。

译者注:这里的 UseSqlite会报错,可能是作者疏忽了。要使用 SQLite,必须安装开发包,请在控制台输入如下命令进行安装:
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
安装完成后会提示 restore,点确定即可,也可使用dotnet restore命令手动 restore。完成后代码就不再报错了。

为了完成存储和访问模型数据所需的一组类,需要使用数据库上下文类的IRepository接口的实现。向 Models 文件夹中添加一个名为 EFRepository.cs 的新文件,并添加清单13-20中所示的代码。

清单 13-20:PartyInvites/Models 文件夹下的 EFRepository.cs 文件的内容

using System.Collections.Generic;

namespace PartyInvites.Models
{
    public class EFRepository : IRepository
    {
        private ApplicationDbContext context = new ApplicationDbContext();
        public IEnumerable<GuestResponse> Responses => context.Invites;
        public void AddResponse(GuestResponse response)
        {
            context.Invites.Add(response);
            context.SaveChanges();
        }
    }
}

EFRepository类遵循与我在第8章中用来建立运动商店数据库的类似模式。在清单13-21中,我在Startup类的ConfigureServices方法中添加了一条配置语句,该方法告诉 ASP.NET 在依赖项注入特性(第18章中将描述)需要IRepository接口的实现时,创建EFRepository类。

清单 13-21:Partyinvites 文件夹下的 Startup.cs 文件,配置存储库

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using PartyInvites.Models;

namespace PartyInvites
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<IRepository,EFRepository>();
            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseDeveloperExceptionPage();
            app.UseStatusCodePages();
            app.UseStaticFiles();
            app.UseMvcWithDefaultRoute();
        }
    }
}

创建数据库

在本书的其余部分中,每当我需要演示需要数据持久化时,都会使用 LocalDB,它是 Microsoft SQL Server 的简化版本。但是 LocalDB 功能只在 Windows 上可用,这意味着在其他平台上创建 ASP.NET Core MVC 应用程序时需要另一种选择。LocalDB 的最佳替代方案是 SQLite,它是一个跨平台的零配置数据库,可以嵌入应用程序中,微软已经在 Entity Framework Core 中包含了对它的支持,这是 ASP.NET Core MVC 应用程序通常使用的数据访问层。在接下来的部分中,我将介绍如何向项目中添加 SQLite 并将其用作派对响应的数据存储。


利用 SQLite 进行开发

LocaldB 之所以是如此有用的工具之一,是因为它允许使用 SQL Server 数据库引擎进行开发,这使得向生产 SQL Server 环境的转换变得简单且基本没有风险。SQLite 是一个优秀的数据库,但它并不适合大型的 Web 应用程序,这意味着在部署 MVC 应用程序时需要转换到另一个数据库。可以使用我在第14章中描述的项目配置功能来简化配置更改,但您需要在生产环境中彻底测试应用程序,以暴露生产数据库引入的任何差异。

请参见https://www.sqlite.org/whentouse.html,如果您不确定是否在生产中使用 SQLite。对于 SQLite 擅长哪些,哪些不擅长,此页面提供了很好的介绍。

需要注意的一个问题是,SQLite 不支持 Entity Framework Core 可以为其他数据库生成的全部架构更改。在开发中使用 SQLite 时,这通常不是一个问题,因为您可以删除数据库文件并生成一个具有干净架构的新文件。但是,如果您正在考虑使用 SQLite 部署应用程序,则会使问题复杂化。

如果您想在开发和生产环境中使用相同的数据库,请参阅http://ef.readthedocs.io/en/latest/providers/index.html中支持的 Entity Framework Core 数据库列表。在我写这篇文章时,列表很短,但微软已经宣布支持比 SQLite 更适合部署的数据库,并且还可以在非 Windows 平台上运行。


添加数据库包

包含用于创建和应用数据库迁移的命令行工具的 Nuget 包必须手动添加到项目中。打开 PartyInvites.csproj 文件并添加清单13-22中所示的元素。

清单 13-22:PartyInvites 文件夹下的 PartyInvites.csproj 文件,添加 NuGet 包

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Folder Include="wwwroot\" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.App" />
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" />
  </ItemGroup>

</Project>

保存更改并在 PartyInvites 文件夹中运行清单13-23所示的命令,以确保下载和安装新包。

清单 13-23:安装 NuGet 包

dotnet restore

译者注:.NET Core 2.1 已经内置了Microsoft.EntityFrameworkCore.Tools.DotNet。所以不再需要手动添加,这一小节的内容可以无视。

创建并应用数据库迁移

创建数据库遵循与 Visual Studioe 相同的过程。要创建初始的数据库迁移,请在 PartyInvites 文件夹中运行清单13-24中的命令。

清单 13-24:创建数据库迁移

dotnet ef migrations add Initial

Entity Framework Core 将创建一个名为 Migrations 的文件夹,它包含了用于建立数据库架构的 C# 类。要应用数据库迁移,请在 PartyInvites 文件夹中运行清单13-25所示的命令,该命令将在 PartyInvites 文件夹中创建数据库。

清单 13-25:应用数据库迁移

dotnet ef database update

Visual Studio Code 不支持浏览 Sqite 数据库,但您可以在http://sqlitebrowser.org上找到用于 Windows、MacOS 和 Linux 的优秀开源工具。

创建控制器和视图

在本节中,我将控制器和视图添加到应用程序中。首先,我创建了 PartyInvites/Controllers 文件夹,并在其中添加了一个名为 HomeController.cs 的文件,用于创建清单13-26所示的控制器。

清单 13-26:PartyInvites/Controllers 文件夹下的 HomeController.cs 文件的内容

using System;
using Microsoft.AspNetCore.Mvc;
using PartyInvites.Models;
using System.Linq;

namespace PartyInvites.Controllers
{
    public class HomeController : Controller
    {
        private IRepository repository;
        public HomeController(IRepository repo) =>
        this.repository = repo;
        public ViewResult Index()
        {
            int hour = DateTime.Now.Hour;
            ViewBag.Greeting = hour < 12 ? "Good Morning" : "Good Afternoon";
            return View("MyView");
        }

        [HttpGet]
        public ViewResult RsvpForm() => View();

        [HttpPost]
        public ViewResult RsvpForm(GuestResponse guestResponse)
        {
            if (ModelState.IsValid)
            {
                repository.AddResponse(guestResponse);
                return View("Thanks", guestResponse);
            }
            else
            {
                // there is a validation error
                return View();
            }
        }

        public ViewResult ListResponses() =>
            View(repository.Responses.Where(r => r.WillAttend == true));
    }
}

为了设置内置的标签助手,我创建了一个 PartyInvites/Views 文件夹,并添加了一个名为 _ViewImports.cshtml 的文件,其中包含清单13-27所示的表达式。

清单 13-27:PartyInvites/Views 文件夹下的 _ViewImports.cshtml 文件的内容

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

接下来,我创建了一个 Views/Home 文件夹,并添加了一个名为 MyView.cshtml 的文件,它是由清单13-26中的Index action 方法选择的视图。

清单 13-28:PartyInvites/Views/Home 文件夹下的 MyView.cshtml 文件的内容

@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    <link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.css" />
</head>
<body class="p-2">
    <div class="text-center">
        <h3>We're going to have an exciting party!</h3>
        <h4>And you are invited</h4>
        <a class="btn btn-primary" asp-action="RsvpForm">RSVP Now</a>
    </div>
</body>
</html>

我在 Views/Home 文件夹中添加了一个名为 RsvpForm.cshtml 的文件,并添加了清单13-29所示的内容。此视图提供受邀者填写的 HTML 表单,以接受或拒绝他们对聚会的邀请。

清单 13-29:PartyInvites/Views/Home 文件夹下的 RsvpForm.cshtml 文件的内容

@model PartyInvites.Models.GuestResponse

@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>RsvpForm</title>
    <link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.css" />
</head>
<body>
    <div class="m-2">
        <div class="text-center"><h4>RSVP</h4></div>
        <form class="p-1" asp-action="RsvpForm" method="post">
            <div asp-validation-summary="All"></div>
            <div class="form-group">
                <label asp-for="Name">Your name:</label>
                <input class="form-control" asp-for="Name" />
            </div>
            <div class="form-group">
                <label asp-for="Email">Your email:</label>
                <input class="form-control" asp-for="Email" />
            </div>
            <div class="form-group">
                <label asp-for="Phone">Your phone:</label>
                <input class="form-control" asp-for="Phone" />
            </div>
            <div class="form-group">
                <label>Will you attend?</label>
                <select class="form-control" asp-for="WillAttend">
                    <option value="">Choose an option</option>
                    <option value="true">Yes, I'll be there</option>
                    <option value="false">No, I can't come</option>
                </select>
            </div>
            <div class="text-center">
                <button class="btn btn-primary" type="submit">
                    Submit RSVP
                </button>
            </div>
        </form>
    </div>
</body>
</html>

下一个视图文件名为 Thanks.cshtml,它也是在 Thanks.cshtml 文件夹中创建的,其内容如清单13-30所示,在来宾提交响应时显示。

清单 13-30:PartyInvites/Views/Home 文件夹下的 Thanks.cshtml 文件的内容

@model PartyInvites.Models.GuestResponse

@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Thanks</title>
    <link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.css" />
</head>
<body class="text-center">
    <p>
        <h1>Thank you, @Model.Name!</h1>
        @if (Model.WillAttend == true) {
            @:It's great that you're coming. The drinks are already in the fridge!
        } else {
            @:Sorry to hear that you can't make it, but thanks for letting us know.
        }
    </p>
    Click <a asp-action="ListResponses">here</a>
    to see who is coming.
</body>
</html>

最后一个视图名为 ListResponses.cshtml,与本例中的其他视图一样,它被添加到 Views/Home 文件夹中。该视图使用清单13-31所示的标记显示应邀来宾列表。

清单 13-31:PartyInvites/Views/Home 文件夹下的 ListResponses.cshtml 文件的内容

@model IEnumerable<PartyInvites.Models.GuestResponse>

@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.css" />
    <title>Responses</title>
</head>
<body>
    <div class="m-1 p-1">
        <h2>Here is the list of people attending the party</h2>
        <table class="table table-sm table-striped table-bordered">
            <thead>
                <tr><th>Name</th><th>Email</th><th>Phone</th></tr>
            </thead>
            <tbody>
                @foreach (PartyInvites.Models.GuestResponse r in Model) {
                    <tr><td>@r.Name</td><td>@r.Email</td><td>@r.Phone</td></tr>
                }
            </tbody>
        </table>
    </div>
</body>
</html>

在 PartyInvites 项目中运行dotnet run命令来编译项目并启动 ASP.NET Core 运行时。一旦应用程序启动,您可以通过导航到 http://localhost:5000 查看完整的应用程序,如图13-10所示。

图13-10 运行已完成的应用程序

在 Visual Studio Code 中进行单元测试

使用 Visual Studio Code 进行单元测试的过程类似于 Visual Studio。第一步是为单元测试创建一个单独的项目。在 InvitesProject 文件夹中创建一个名为 Tests 的文件夹,并在新文件夹中运行清单13-32所示的命令来创建单元测试项目。

清单 13-32:创建单元测试项目

dotnet new xunit --language C# --framework netcoreapp2.1

在 Tests 文件夹中运行清单13-33所示的命令,以添加对应用程序项目的引用,以便它包含的类可用于测试。

清单 13-33:添加应用程序项目的引用

dotnet add reference ../PartyInvites/PartyInvites.csproj

创建单元测试

单元测试是按照第7章中描述的那样创建的。我在测试文件夹中添加了一个名为 HomeControllerTests.cs 的新类文件,清单13-34所示的内容。

清单 13-34:Tests 文件夹下的 HomeControllerTests.cs 文件的内容

using System;
using System.Collections.Generic;
using PartyInvites.Controllers;
using PartyInvites.Models;
using Xunit;
using Microsoft.AspNetCore.Mvc;
using System.Linq;

namespace Tests {
    public class HomeControllerTests {
        [Fact]
        public void ListActionFiltersNonAttendees() {
            //Arrange
            HomeController controller = new HomeController(new FakeRepository());
            // Act
            ViewResult result = controller.ListResponses();
            // Assert
            Assert.Equal(2, (result.Model as IEnumerable<GuestResponse>).Count());
            }
        }
        class FakeRepository : IRepository {
            public IEnumerable<GuestResponse> Responses =>
                new List<GuestResponse> {
                    new GuestResponse { Name = "Bob", WillAttend = true },
                    new GuestResponse { Name = "Alice", WillAttend = true },
                    new GuestResponse { Name = "Joe", WillAttend = false }
                };
            public void AddResponse(GuestResponse response) {
                throw new NotImplementedException();
        }
    }
}

这是一个标准的 xUnit 测试,它检查 Home 控制器中的ListResponses action,并正确地筛选出WillAttend属性为false的存储库中的GuestResponse对象。

运行测试

要在项目中执行单元测试,请在 Tests 文件夹中运行如清单13-35所示的命令。

清单 13-35:运行单元测试

dotnet test

项目中的所有测试都将运行并显示结果,产生的输出如下:

Starting test execution, please wait...
[xUnit.net 00:00:00.6731479] Discovering: Tests
[xUnit.net 00:00:00.7900132] Discovered: Tests
[xUnit.net 00:00:00.8432715] Starting: Tests
[xUnit.net 00:00:00.9967614] Finished: Tests
Total tests: 2. Passed: 2. Failed: 0. Skipped: 0.
Test Run Successful.
Test execution time: 1.6974 Seconds

结果中显示了两个测试,因为项目模板包含一个名为 UnitTest1.cs 的文件,其中包含一个空单元测试。您可以删除该文件,如第7章所示。

总结

在本章中,我简要概述了使用 Visual Studio Code 的情况,它是一种轻量级的开发工具,支持 Windows、MacOS 和 Linux 上的 ASP.NET Core MVC 开发。Visual Studio Code 还没有完全取代完整的 Visual Studio 产品,但它提供了创建 MVC 应用程序所需的核心功能,并且正在由微软每月发布新版本加以增强。

这是本书第1部分的结尾。在第2部分中,我开始深入了解细节,并向您展示我用来创建应用程序的特性是如何深入地工作的。

;

© 2018 - IOT小分队文章发布系统 v0.3